// Project: EnumDataSourceControl, File: EnumDataSource.cs
// Namespace: Salient.Web.UI.WebControls, Class: EnumDataSource
// Author: Sky Sanders (sky.sanders@gmail.com)

// Creation date: 10/15/2008 8:24 PM
// Last modified: 10/16/2008 7:19 AM




#region Using directives
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Drawing;
#endregion

/// <summary>
/// Salient. web. UI. web controls
/// </summary>
namespace Salient.Web.UI.WebControls
{
    /// <remarks>
    /// <para>EnumDataSource provides 
    /// <list type="bullet">
    /// <item><description>a queryable datasource base on arbitrary enum types and is suitable for asp.net declarative databinding.</description></item>
    /// <item><description>methods for querying specific values. Suitable for displaying enum description in non-list controls such as the label in an ItemTemplate</description></item>
    /// </list> </para>
    /// <para>
    /// Intended usage is for combobox lookups for numeric database fields that represent an enum value in your system.
    /// </para>
    /// <para>
    /// Only one instance of EnumDataSource is required.
    /// </para>
    /// <para>
    /// </para>
    /// <example>
    /// Programmatic Usage: Binding to a list
    /// <code>
    /// DropDownList1.DataSource = EnumDataSource1;
    /// DropDownList1.DataMember = "System.Drawing.KnownColor";
    /// DropDownList1.DataValueField = "IntegralValue";
    /// DropDownList1.DataTextField = "Description";
    /// </code>
    /// Programmatic Usage: Querying distinct value
    /// <code>
    /// // using string arguments
    /// Label1.Text = EnumDataSource1.GetDescription("System.Drawing.KnownColor","ControlDark")
    /// // using type arguments
    /// Label1.Text = EnumDataSource1.GetDescription(System.Drawing.KnownColor,System.Drawing.KnownColor.ControlDark)
    /// </code>
    /// Declarative Usage: Binding to a list
    /// <code>
    /// &lt;asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="EnumDataSource1" DataTextField="Description" DataValueField="IntegralValue" DataMember="ReferenceLibrary.TestEnum" SelectedValue="&lt;%# Bind('myEnumBasedIntField') %>">&lt;/asp:DropDownList>
    /// </code>
    /// Declarative Usage: Querying distinct value
    /// <code>
    /// &lt;asp:TextBox ID="TextBox1" runat="server" Text='&lt;%# Bind("enum") %>'>&lt;/asp:TextBox>
    /// </code>
    /// </example>
    /// </remarks>
    [ToolboxBitmap(typeof(EnumDataSource), "EnumDataSource.png")]
    public class EnumDataSource : DataSourceControl
    {

        private static Dictionary<string, EnumTypeInfoView> _types;

        /// <summary>
        /// If enum value is decorated with Description attribute, that value is returned.
        /// Otherwise the enum name is returned.
        /// </summary>
        /// <param name="enumType">e.g. typeof(System.Drawing.KnownColor)</param>
        /// <param name="value">any value that can be parsed by the specified Enum type</param>
        /// <returns></returns>
        public string GetDescription(Type enumType, object value)
        {
            object enumValue = Enum.Parse(enumType, value.ToString());
            return Salient.Util.EnumExtensions.GetDescription((Enum)enumValue);
        } // GetDescription(enumType, value)

        /// <summary>
        /// If enum value is decorated with Description attribute, that value is returned.
        /// Otherwise the enum name is returned.
        /// </summary>
        /// <param name="enumTypeFullName">e.g. "System.Drawing.KnownColor"</param>
        /// <param name="value">any value that can be parsed by the specified Enum type</param>
        /// <returns></returns>
        public string GetDescription(string enumTypeFullName, object value)
        {
            return GetDescription(Salient.Util.EnumExtensions.GetEnumType(enumTypeFullName), value);

        } // GetDescription(enumTypeFullName, value)

        /// <summary>
        /// Gets typed enum value from type and description.
        /// </summary>
        /// <param name="enumType">e.g. typeof(System.Drawing.KnownColor)</param>
        /// <param name="Description">"ControlDark"</param>
        /// <returns>e.g. System.Drawing.KnownColor.ControlDark</returns>
        /// <remarks>not implemented - need to guard against duplicate descriptions coming out before i accept them back in.</remarks>
        public Enum GetValue(Type enumType, string Description)
        {
            return Salient.Util.EnumExtensions.GetValue(enumType, Description);

        } // GetValue(enumType, Description)

        /// <summary>
        /// Gets typed enum value from typename and description.
        /// </summary>
        /// <param name="enumTypeFullName">e.g. "System.Drawing.KnownColor"</param>
        /// <param name="Description">e.g. "ControlDark"</param>
        /// <returns>e.g. System.Drawing.KnownColor.ControlDark</returns>
        /// <remarks>not implemented - need to guard against duplicate descriptions coming out before i accept them back in.</remarks>
        public Enum GetValue(string enumTypeFullName, string Description)
        {
            return Salient.Util.EnumExtensions.GetValue(enumTypeFullName, Description);

        } // GetValue(enumTypeFullName, Description)

        /// <summary>
        /// Returns a DataSourceView of EnumInfo[] for specified type.
        /// </summary>
        /// <param name="viewName">enum type FullName e.g. System.Drawing.KnownColor</param>
        /// <returns></returns>
        protected override DataSourceView GetView(string viewName)
        {
            if (string.IsNullOrEmpty(viewName))
                return null;

            if (_types == null)
                _types = new Dictionary<string, EnumTypeInfoView>();

            if (!_types.ContainsKey(viewName))
            {
                Type type = Salient.Util.EnumExtensions.GetEnumType(viewName);
                _types.Add(viewName, new EnumTypeInfoView(this, new EnumTypeInfo(type)));
            } // if

            return _types[viewName];
        } // GetView(viewName)

    } // class EnumDataSource
} // namespace Salient.Web.UI.WebControls
